using Microsoft.Extensions.Logging; // 引入日志功能

using UniversalAdmin.Application.DTOs; // 引入DTO相关命名空间
using UniversalAdmin.Domain.Entities; // 引入实体相关命名空间
using UniversalAdmin.Domain.Repositories; // 引入仓储相关命名空间

namespace UniversalAdmin.Application.Services // 应用服务命名空间
{
    /// <summary>
    /// 角色服务实现类，包含角色的增删改查及权限分配等业务逻辑
    /// </summary>
    public class RoleService : IRoleService
    {
        // 角色仓储，用于操作角色数据表
        private readonly IRepository<Role> _roleRepository;
        // 日志记录器
        private readonly ILogger<RoleService> _logger;
        // 角色权限仓储，用于操作角色与权限的关系表
        private readonly IRepository<RolePermission> _rolePermissionRepository;

        /// <summary>
        /// 构造函数，注入所需仓储和日志服务
        /// </summary>
        public RoleService(IRepository<Role> roleRepository, ILogger<RoleService> logger, IRepository<RolePermission> rolePermissionRepository)
        {
            _roleRepository = roleRepository; // 赋值角色仓储
            _logger = logger; // 赋值日志服务
            _rolePermissionRepository = rolePermissionRepository; // 赋值角色权限仓储
        }

        /// <summary>
        /// 获取所有角色列表
        /// </summary>
        /// <returns>角色DTO列表</returns>
        public async Task<List<RoleDto>> GetRolesAsync()
        {
            var roles = await _roleRepository.ListAllAsync(); // 查询所有角色实体
            var roleDtos = roles.Select(r => new RoleDto(r.Id, r.Name ?? "", r.Description)).ToList(); // 转换为DTO
            return roleDtos; // 返回DTO列表
        }

        /// <summary>
        /// 根据ID获取单个角色信息
        /// </summary>
        /// <param name="id">角色ID</param>
        /// <returns>角色DTO或null</returns>
        public async Task<RoleDto?> GetRoleByIdAsync(Guid id)
        {
            var role = await _roleRepository.GetByIdAsync(id); // 根据ID查找角色
            if (role == null) // 未找到角色
            {
                _logger.LogWarning("Role not found with ID {RoleId}", id); // 记录警告日志
                throw new ArgumentException("角色不存在"); // 抛出异常
            }
            return new RoleDto(role.Id, role.Name ?? "", role.Description); // 返回角色DTO
        }

        /// <summary>
        /// 创建新角色
        /// </summary>
        /// <param name="dto">创建角色的DTO</param>
        /// <returns>新建角色的DTO</returns>
        public async Task<RoleDto> CreateRoleAsync(CreateRoleDto dto)
        {
            // 判断角色名是否已存在，防止重复
            if (await _roleRepository.AnyAsync(r => r.Name == dto.Name))
            {
                _logger.LogWarning("Role with name {RoleName} already exists", dto.Name); // 记录警告日志
                throw new ArgumentException("角色名称已存在"); // 抛出异常
            }

            // 若描述为空则赋默认值
            string description = !string.IsNullOrWhiteSpace(dto.Description)
                               ? dto.Description // 使用传入描述
                               : "默认描述"; // 默认描述

            // 创建角色实体
            var role = new Role { Name = dto.Name, Description = description };
            await _roleRepository.AddAsync(role); // 添加到仓储
            _logger.LogInformation("Role created with ID {RoleId}", role.Id); // 记录信息日志
            return new RoleDto(role.Id, role.Name, role.Description); // 返回新建角色DTO
        }

        /// <summary>
        /// 更新角色信息
        /// </summary>
        /// <param name="id">角色ID</param>
        /// <param name="dto">更新角色的DTO</param>
        /// <returns>更新后的角色DTO或null</returns>
        public async Task<RoleDto?> UpdateRoleAsync(Guid id, UpdateRoleDto dto)
        {
            var role = await _roleRepository.GetByIdAsync(id); // 查找角色
            if (role == null) // 未找到角色
            {
                _logger.LogWarning("Role not found with ID {RoleId}", id); // 记录警告日志
                throw new ArgumentException("角色不存在");
            }

            role.Name = dto.Name;
            role.Description = dto.Description ?? "默认描述";
            await _roleRepository.UpdateAsync(role);
            _logger.LogInformation("Role updated with ID {RoleId}", id);
            return new RoleDto(role.Id, role.Name, role.Description);
        }

        public async Task<bool> DeleteRoleAsync(Guid id)
        {
            var role = await _roleRepository.GetByIdAsync(id);
            if (role == null)
            {
                _logger.LogWarning("Role not found with ID {RoleId}", id);
                return false;
            }

            if (role.Name == "SuperAdmin")
            {
                _logger.LogWarning("SuperAdmin role cannot be deleted");
                throw new ArgumentException("超级管理员角色不能删除");
            }

            if (await _roleRepository.AnyAsync(r => r.UserRoles.Any(ur => ur.RoleId == id)))
            {
                _logger.LogWarning("Role {RoleId} is in use and cannot be deleted", id);
                throw new ArgumentException("该角色已被用户使用，不能删除");
            }

            try
            {
                await _roleRepository.DeleteAsync(role);
                _logger.LogInformation("Role deleted with ID {RoleId}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting role with ID {RoleId}", id);
                return false;
            }
        }

        public async Task AssignPermissionsAsync(Guid roleId, List<Guid> permissionIds)
        {
            var role = await _roleRepository.GetByIdAsync(roleId);
            if (role == null)
            {
                _logger.LogWarning("Role not found with ID {RoleId}", roleId);
                throw new ArgumentException("角色不存在");
            }

            // 删除现有权限
            var existingPermissions = await _rolePermissionRepository.ListAsync(rp => rp.RoleId == roleId);
            await _rolePermissionRepository.RemoveRangeAsync(existingPermissions);

            // 添加新的权限
            var newPermissions = permissionIds.Select(permissionId => new RolePermission
            {
                RoleId = roleId,
                PermissionId = permissionId    // Guid类型
            }).ToList();

            await _rolePermissionRepository.AddRangeAsync(newPermissions);
            _logger.LogInformation("Permissions updated for role with ID {RoleId}", roleId);
        }
    }
}